package model

import (
	"encoding/json"
	"errors"
	"time"

	"go.mongodb.org/mongo-driver/bson"
)

type MsgType int

const (
	MsgTypeText MsgType = iota
	MsgTypeFile
	MsgTypeImage
	MsgTypeVideo
	MsgTypeAudio
	MsgTypeSystem
	MsgTypeHistory
	MsgTypeConversationList
	MsgTypeSubscribe // 订阅消息,订阅当前会话目标的状态变化，如在线、离线等
)

type EventCodeType int

const (
	// 下发
	// 断开连接
	EventCodeDisconnect EventCodeType = iota

	// 上传
	// 删除会话
	EventCodeRemoveConversation
	// 置顶会话
	EventCodeTopConversation
	// 取消置顶会话
	EventCodeUnTopConversation
)

type SubscribeMsg struct {
	Online bool `json:"online" bson:"online"`
}

type TextMsg struct {
	Content string `json:"content" bson:"content"`
}

type FileMsg struct {
	Url  string `json:"url" bson:"url"`
	Name string `json:"name" bson:"name"`
}

type SystemMsg struct {
	EventCode EventCodeType `json:"eventCode" bson:"eventCode"`
	Event     string        `json:"event" bson:"event"`
}

type HistoryMsg struct {
	Count    int64     `json:"count" bson:"count"`
	Deadline time.Time `json:"deadline" bson:"deadline"`
	MsgList  []Msg     `json:"msgList" bson:"msgList"`
}

type ConversationListMsg struct {
	Count            int64          `json:"count" bson:"count"`
	ConversationList []Conversation `json:"conversationList" bson:"conversationList"`
}

type MsgT[T any] struct {
	FromId    uint      `json:"fromId" bson:"fromId"`
	ToId      uint      `json:"toId" bson:"toId"`
	Type      MsgType   `json:"type" bson:"type"`
	Body      T         `json:"body" bson:"body"`
	CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
}

type Msg MsgT[any]

func (m *Msg) UnmarshalBSON(data []byte) error {
	var rawMsg MsgT[bson.Raw]
	if err := bson.Unmarshal(data, &rawMsg); err != nil {
		return err
	}
	// 使用注释部分无法将bson解析为struct
	// var body any
	switch rawMsg.Type {
	case MsgTypeText:
		// body = &TextMsg{}
		var body TextMsg
		if err := bson.Unmarshal(rawMsg.Body, &body); err != nil {
			return err
		}
		m.Body = body
	case MsgTypeFile, MsgTypeImage, MsgTypeVideo, MsgTypeAudio:
		// body = &FileMsg{}
		var body FileMsg
		if err := bson.Unmarshal(rawMsg.Body, &body); err != nil {
			return err
		}
		m.Body = body
	case MsgTypeSystem:
		// body = &SystemMsg{}
		var body SystemMsg
		if err := bson.Unmarshal(rawMsg.Body, &body); err != nil {
			return err
		}
		m.Body = body
	case MsgTypeHistory:
		// body = &HistoryMsg{}
		var body HistoryMsg
		if err := bson.Unmarshal(rawMsg.Body, &body); err != nil {
			return err
		}
		m.Body = body
	case MsgTypeConversationList:
		var body ConversationListMsg
		if err := bson.Unmarshal(rawMsg.Body, &body); err != nil {
			return err
		}
	case MsgTypeSubscribe:
		var body SubscribeMsg
		if err := bson.Unmarshal(rawMsg.Body, &body); err != nil {
			return err
		}
	default:
		return errors.New("unknown msg type")
	}
	// if err := bson.Unmarshal(rawMsg.Body, &body); err != nil {
	// 	return err
	// }
	// m.Body = body
	m.FromId = rawMsg.FromId
	m.ToId = rawMsg.ToId
	m.Type = rawMsg.Type
	m.CreatedAt = rawMsg.CreatedAt
	return nil
}

func (m *Msg) UnmarshalJSON(data []byte) error {
	var rawMsg MsgT[json.RawMessage]
	if err := json.Unmarshal(data, &rawMsg); err != nil {
		return err
	}
	var body any
	switch rawMsg.Type {
	case MsgTypeText:
		body = &TextMsg{}
	case MsgTypeFile, MsgTypeImage, MsgTypeVideo, MsgTypeAudio:
		body = &FileMsg{}
	case MsgTypeSystem:
		body = &SystemMsg{}
	case MsgTypeHistory:
		body = &HistoryMsg{}
	case MsgTypeConversationList:
		body = &ConversationListMsg{}
	case MsgTypeSubscribe:
		body = &SubscribeMsg{}
	default:
		return errors.New("unknown msg type")
	}
	if err := json.Unmarshal(rawMsg.Body, &body); err != nil {
		return err
	}
	m.Body = body
	m.FromId = rawMsg.FromId
	m.ToId = rawMsg.ToId
	m.Type = rawMsg.Type
	m.CreatedAt = rawMsg.CreatedAt
	return nil
}
